package com.example.private_auto_install.ftpGIt;

import com.jcraft.jsch.*;
import org.apache.log4j.Logger;

import java.io.*;
import java.util.*;

/**
 * @Description: 远程连接 --主要处理，执行远程命令，以及上传服务器文件
 * @Author: by
 * @Date: 2022-03-01
 **/
public class Ftp {
    //打印log日志
    public static Logger publishLogProcess = Logger.getLogger("publishLogProcess");

    private static Date last_push_date = null;

    public Session sshSession;

    private ChannelSftp channel;

    /**
     * 这几个属性会在initConfig 中重置
     */
    private static String USER = "root";
    private static String PASSWORD = "admin@123";
    private String HOST = "";
    private static int DEFAULT_SSH_PORT = 22;

    private static final int CONNECT_TIMEOUT = 3000;

    private static ThreadLocal<Ftp> sftpLocal = new ThreadLocal<Ftp>();

    public static void main(String[] args) {
        try {

//            Ftp.uploadingFiles();
            boolean flag = Ftp.uploadPublishFiles();
//            boolean flag = Ftp.uploadBaseFile(MainIndex.projectPath);
            System.out.println(flag);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Ftp.release();
        }
    }

    /**
     * 增量更新文件
     *
     * @return
     */
    public static boolean uploadingFiles() {
        Ftp ftp = Ftp.getSftpUtil();
        String directory = UtilMonitor.getProperties1("uploadTargetPath", "ftp");
        String uploadFile = JGitHandle.updateSavePath + File.separator + "project_biology";
        List<File> files = UtilFile.getAllFiles(uploadFile, new ArrayList<File>());
        publishLogProcess.info("需要上传的增量文件个数" + files.size());
        boolean flag = true;
        for (int i = 0; i < files.size(); i++) {
            File file = files.get(i);
            boolean flag2 = ftp.singleUpload(directory, uploadFile, file,file.getName());
            if (!flag2) {
                flag = false;
            }
        }
        return flag;
    }

    /**
     * 构造函数
     *
     * @throws Exception
     */
    public Ftp() throws Exception {
//        Ftp.initConfig();
        JSch jsch = new JSch();
        jsch.getSession(USER, this.HOST, DEFAULT_SSH_PORT);
        //根据用户名，密码，端口号获取session
        sshSession = jsch.getSession(USER, this.HOST, DEFAULT_SSH_PORT);
        sshSession.setPassword(PASSWORD);
        //修改服务器/etc/ssh/sshd_config 中 GSSAPIAuthentication的值yes为no，解决用户不能远程登录
        sshSession.setConfig("userauth.gssapi-with-mic", "no");

        //为session对象设置properties,第一次访问服务器时不用输入yes
        sshSession.setConfig("StrictHostKeyChecking", "no");
        sshSession.connect();


        //获取sftp通道
        channel = (ChannelSftp) sshSession.openChannel("sftp");
        channel.connect();
        // logger.info("连接ftp成功!" + sshSession);
    }

    /**
     * 构造函数
     *
     * @throws Exception
     */
    public Ftp(String host) {
//        Ftp.initConfig();
        this.HOST = host;
        JSch jsch = new JSch();
        try {
            jsch.getSession(USER, host, DEFAULT_SSH_PORT);

            //根据用户名，密码，端口号获取session
            sshSession = jsch.getSession(USER, host, DEFAULT_SSH_PORT);
            sshSession.setPassword(PASSWORD);
            //修改服务器/etc/ssh/sshd_config 中 GSSAPIAuthentication的值yes为no，解决用户不能远程登录
            sshSession.setConfig("userauth.gssapi-with-mic", "no");

            //为session对象设置properties,第一次访问服务器时不用输入yes
            sshSession.setConfig("StrictHostKeyChecking", "no");
            sshSession.connect();


            //获取sftp通道
            channel = (ChannelSftp) sshSession.openChannel("sftp");
            channel.connect();
            // logger.info("连接ftp成功!" + sshSession);
        } catch (JSchException e) {
            e.printStackTrace();
        }
    }


    public static void initConfig() {
//        Properties ftpConfig = UtilMonitor.getAllProperties("ftp");
//        Ftp.USER = ftpConfig.getProperty("user");
//        Ftp.PASSWORD = ftpConfig.getProperty("password");
//        Ftp.HOST = ftpConfig.getProperty("host");

    }


    /**
     * 是否已连接
     *
     * @return
     */
    private boolean isConnected() {
        return null != channel && channel.isConnected();
    }

    /**
     * 获取本地线程存储的sftp客户端
     *
     * @return
     * @throws Exception
     */
    public static Ftp getSftpUtil() {
        //获取本地线程
        Ftp sftpUtil = sftpLocal.get();
        if (null == sftpUtil || !sftpUtil.isConnected()) {
            //将新连接防止本地线程，实现并发处理
            try {
                sftpLocal.set(new Ftp());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return sftpLocal.get();
    }

    public static Ftp getSftpUtil(String IP) {
        //获取本地线程
        Ftp sftpUtil = sftpLocal.get();
        if (null == sftpUtil || !sftpUtil.isConnected()) {
            //将新连接防止本地线程，实现并发处理
            try {
                sftpLocal.set(new Ftp());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return sftpLocal.get();
    }

    /**
     * 释放本地线程存储的sftp客户端
     */
    public static void release() {
        if (null != sftpLocal.get()) {
            sftpLocal.get().closeChannel();
            // logger.info("关闭连接" + sftpLocal.get().sshSession);
            sftpLocal.set(null);

        }
    }

    /**
     * 关闭通道
     *
     * @throws Exception
     */
    public void closeChannel() {
        if (null != channel) {
            try {
                channel.disconnect();
            } catch (Exception e) {
                // logger.error("关闭SFTP通道发生异常:", e);
            }
        }
        if (null != sshSession) {
            try {
                sshSession.disconnect();
            } catch (Exception e) {
                // logger.error("SFTP关闭 session异常:", e);
            }
        }
    }

    /**
     * singleUpload  方法的升级方法
     *
     * @param files
     * @param directory
     * @param outDeletePathStr
     * @return
     */
    public boolean listFileUpload(List<File> files, String directory, String outDeletePathStr) {
        Ftp ftp = Ftp.getSftpUtil();
        System.out.println("上传文件数为" + files.size());
        boolean flag = true;
        for (int i = 0; i < files.size(); i++) {
            File file = files.get(i);
            boolean flag2 = ftp.singleUpload(directory, outDeletePathStr, file,file.getName());
            if (!flag2) {
                flag = false;
            }
        }
        return flag;
    }

    /**
     * @param directory        上传ftp的目录  例： /home/test
     * @param outDeletePathStr file中需要去掉的前缀字符串
     */
    public boolean singleUpload(String directory, String outDeletePathStr, File file,String fileName) {
        String filePath = "";
        try {        //执行列表展示ls 命令
            // this.remoteExecute("mkdir -p " + directory);
            Vector vector = channel.ls(directory);        //执行盘符切换cd 命令
            channel.cd(directory);

            InputStream input = new BufferedInputStream(new FileInputStream(file));
//
//            filePath = file.getAbsolutePath().replace(outDeletePathStr, "");
//            filePath = filePath.substring(0, filePath.lastIndexOf(File.separator));
//            String targetPath = directory + filePath;
//            targetPath = targetPath.replaceAll("\\\\", "/");
//
//            String command = "mkdir -p " + targetPath;
//            System.out.println("执行命令为：" + command);
            // 执行创建文件夹的命令
//            this.remoteExecute(command);

            // 这里因为是linux的命令，所有使用左斜杠
            channel.put(input, directory  + fileName);
            try {
                if (input != null) input.close();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(file.getName() + "关闭文件时.....异常!" + e.getMessage());
            }

        } catch (Exception e) {
            publishLogProcess.error(filePath + "上传失败");
            publishLogProcess.error("Ftp" + 224 + "行");
            publishLogProcess.error(e);
        } finally {

        }
        return false;
    }

    /**
     * @param directory  上传ftp的目录
     * @param uploadFile 本地文件目录
     */
    public void upload(String directory, String uploadFile) {
        try {        //执行列表展示ls 命令
            channel.ls(directory);        //执行盘符切换cd 命令
            channel.cd(directory);
            List<File> files = UtilFile.getAllFiles(uploadFile, new ArrayList<File>());
            for (int i = 0; i < files.size(); i++) {
                File file = files.get(i);
                InputStream input = new BufferedInputStream(new FileInputStream(file));

                String filePath = file.getAbsolutePath().replace(uploadFile, "");
                filePath = filePath.substring(1, filePath.length());
                System.out.println(filePath);

                channel.put(input, filePath);
                try {
                    if (input != null) input.close();
                } catch (Exception e) {
                    e.printStackTrace();
                    // logger.error(file.getName() + "关闭文件时.....异常!" + e.getMessage());
                }
                if (file.exists()) {
//                    boolean b = file.delete();
                    // logger.info(file.getName() + "文件上传完毕!删除标识:" + b);
                }
            }
        } catch (Exception e) {
            // logger.error("【子目录创建中】：", e);
            //创建子目录
//            channel.mkdir(directory);
        }

    }

    /**
     * 将发布出来的文件进行上传处理
     */
    public static boolean uploadPublishFiles() {
        //获取发布出来的文件夹
        final String path = MainIndex.projectPath + File.separator + "bin-release" + File.separator + "web";
        File publish = new File(path);
        List<File> list = Arrays.asList(publish.listFiles());
        if (list.size() > 0) {
            Collections.sort(list, new Comparator<File>() {
                public int compare(File o1, File o2) {
                    Long o1L = Long.parseLong(o1.getAbsolutePath().replace(path + File.separator, ""));
                    Long o2L = Long.parseLong(o2.getAbsolutePath().replace(path + File.separator, ""));
                    Long com = o2L - o1L;
                    return com.intValue();
                }
            });
            // 获取到最近发布的一个文件夹
            File lastPublish = list.get(0);
            if (lastPublish.listFiles().length >= 3) { // 说明发布成功
                Ftp ftp = Ftp.getSftpUtil();
                String directory = UtilMonitor.getProperties1("uploadTargetPath", "ftp");
                List<File> files = ftp.getNeedUploadFiles_PCB(lastPublish.getAbsolutePath());
                boolean flag = ftp.listFileUpload(files, directory, lastPublish.getAbsolutePath());
                System.out.println("发布出来的文件---上传结果" + flag);
                return flag;
            } else {
                System.out.println("发布失败---文件目录为" + lastPublish.getAbsolutePath());
                return false;
            }
        }
        return false;
    }

    private List<File> getNeedUploadFiles(String publishPath) {
        //这里分几个文件夹进行上传，
        String Files1Path = publishPath + File.separator + "js";
        List<File> files = UtilFile.getAllFiles(Files1Path, new ArrayList<File>());

        String Files2 = publishPath + File.separator + "resource" + File.separator + "eui_sciencenor" + File.separator + "equipment.xml";
        // 文件
        String File1 = publishPath + File.separator + "manifest.json";
        String File2 = publishPath + File.separator + "resource" + File.separator + "default.res.json";
        String File3 = publishPath + File.separator + "resource" + File.separator + "default.thm.json";
        String File4 = publishPath + File.separator + "resource" + File.separator + "default_01_01.res.json";
        String File5 = publishPath + File.separator + "resource" + File.separator + "default_01_02.res.json";
        String File6 = publishPath + File.separator + "resource" + File.separator + "default_02_01.res.json";
        String File7 = publishPath + File.separator + "resource" + File.separator + "default_02_02.res.json";
        String File8 = publishPath + File.separator + "resource" + File.separator + "default_03_01.res.json";
        String File9 = publishPath + File.separator + "resource" + File.separator + "default_03_02.res.json";
        String File10 = publishPath + File.separator + "resource" + File.separator + "default_04_01.res.json";
        String File11 = publishPath + File.separator + "resource" + File.separator + "default_04_02.res.json";
        String File12 = publishPath + File.separator + "resource" + File.separator + "default_05_01.res.json";
        String File13 = publishPath + File.separator + "resource" + File.separator + "default_05_02.res.json";
        String File14 = publishPath + File.separator + "resource" + File.separator + "default_06_01.res.json";
        String File15 = publishPath + File.separator + "resource" + File.separator + "default_06_02.res.json";
        files.add(new File(Files2));
        files.add(new File(File1));
        files.add(new File(File2));
        files.add(new File(File3));
        files.add(new File(File4));
        files.add(new File(File5));
        files.add(new File(File6));
        files.add(new File(File7));
        files.add(new File(File8));
        files.add(new File(File9));
        files.add(new File(File10));
        files.add(new File(File11));
        files.add(new File(File12));
        files.add(new File(File13));
        files.add(new File(File14));
        files.add(new File(File15));
        return files;
    }

    private List<File> getNeedUploadFiles_PCB(String publishPath) {
        //这里分几个文件夹进行上传，
        String Files1Path = publishPath + File.separator + "js";
        List<File> files = UtilFile.getAllFiles(Files1Path, new ArrayList<File>());

        Files1Path = publishPath + File.separator + "resource";
        files = UtilFile.getAllFiles(Files1Path, files);

        // 文件
        String File1 = publishPath + File.separator + "manifest.json";

        files.add(new File(File1));
        return files;
    }

    /**
     * 上传基础的文件
     *
     * @param projectPath
     * @return
     */
    public static boolean uploadBaseFile(String projectPath) {
        String directory = UtilMonitor.getProperties1("uploadTargetPath", "ftp");
        Ftp ftp = Ftp.getSftpUtil();
        //默认发布的文件夹
        List<String> baselist_folder = Arrays.asList("assets", "config", "css", "img", "js", "resource", "unity3d");
        //默认发布的文件
        List<String> baselist_file = Arrays.asList("config_local.js", "favicon.ico", "index.html");

        List<File> allList = new ArrayList<>();
        for (String str : baselist_folder) {
            String Files1Path = projectPath + File.separator + str;
            List<File> files = UtilFile.getAllFiles(Files1Path, new ArrayList<File>());
            allList.addAll(files);
        }
        for (String str : baselist_file) {
            String Files1Path = projectPath + File.separator + str;
            allList.add(new File(Files1Path));
        }
        boolean flag = ftp.listFileUpload(allList, directory, projectPath);
        return flag;
    }


    /**
     * 上传基础的文件
     *
     * @param projectPath
     * @return
     */
    public static boolean uploadBaseFile_PCB(String projectPath) {
        String directory = UtilMonitor.getProperties1("uploadTargetPath", "ftp");
        Ftp ftp = Ftp.getSftpUtil();
        //默认发布的文件夹
        List<String> baselist_folder = Arrays.asList("config", "css", "icon", "iconfont", "img", "js", "js_prod", "multi-category", "pad", "padjs");
//        默认发布的文件 "resource"
        List<String> baselist_file = Arrays.asList("favicon.ico", "index_list.html", "index_subject_pad.html", "index_explore_pad.html", "index_subject.html", "subj_share.html");

        List<File> allList = new ArrayList<>();
        for (String str : baselist_folder) {
            String Files1Path = projectPath + File.separator + str;
            List<File> files = UtilFile.getAllFiles(Files1Path, new ArrayList<File>());
            allList.addAll(files);
        }
        for (String str : baselist_file) {
            String Files1Path = projectPath + File.separator + str;
            allList.add(new File(Files1Path));
        }
        boolean flag = ftp.listFileUpload(allList, directory, projectPath);
        return flag;
    }

    /**
     * 执行远程命令
     *
     * @param session
     * @param command
     * @return
     * @throws JSchException
     */
    public List<String> remoteExecute(String command) throws JSchException {
//        log.debug(">> {}", command);
        List<String> resultLines = new ArrayList<>();
        ChannelExec channel = null;
        try {
            channel = (ChannelExec) this.sshSession.openChannel("exec");
            channel.setCommand(command);
            InputStream input = channel.getInputStream();
            channel.connect(CONNECT_TIMEOUT);
            try {
                BufferedReader inputReader = new BufferedReader(new InputStreamReader(input));
                String inputLine = null;
                while ((inputLine = inputReader.readLine()) != null) {
//                    log.debug("   {}", inputLine);
                    resultLines.add(inputLine);
                }
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (Exception e) {
//                        log.error("JSch inputStream close error:", e);
                        System.out.println("JSch inputStream close error:" + e);
                    }
                }
            }
        } catch (IOException e) {
//            log.error("IOcxecption:", e);
            System.out.println("IOcxecption" + e);
        } finally {
            if (channel != null) {
                try {
                    channel.disconnect();
                } catch (Exception e) {
//                    log.error("JSch channel disconnect error:", e);
                    System.out.println("JSch inputStream close error:" + e);
                }
            }
        }
        return resultLines;
    }

}

